package top.dyzmj.detty.core.utils.concurrent;

import top.dyzmj.detty.core.utils.ObjectUtil;
import top.dyzmj.detty.core.utils.StringUtil;

import java.util.Locale;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 描述: 一个具有简单命名规则的ThreadFactory实现
 *
 * @author dongYu
 * @date 2021/11/23
 */
public class DefaultThreadFactory implements ThreadFactory {

	private static final AtomicInteger poolId = new AtomicInteger();
	protected final ThreadGroup threadGroup;
	private final AtomicInteger nextId = new AtomicInteger();
	private final String prefix;
	private final boolean daemon;
	private final int priority;

	public DefaultThreadFactory(Class<?> poolType) {
		this(poolType, false, Thread.NORM_PRIORITY);
	}

	public DefaultThreadFactory(String poolName) {
		this(poolName, false, Thread.NORM_PRIORITY);
	}

	public DefaultThreadFactory(Class<?> poolType, boolean daemon) {
		this(poolType, daemon, Thread.NORM_PRIORITY);
	}

	public DefaultThreadFactory(String poolName, boolean daemon) {
		this(poolName, daemon, Thread.NORM_PRIORITY);
	}

	public DefaultThreadFactory(Class<?> poolType, int priority) {
		this(poolType, false, priority);
	}

	public DefaultThreadFactory(String poolName, int priority) {
		this(poolName, false, priority);
	}

	public DefaultThreadFactory(Class<?> poolType, boolean daemon, int priority) {
		this(toPoolName(poolType), daemon, priority);
	}

	public DefaultThreadFactory(String poolName, boolean daemon, int priority, ThreadGroup threadGroup) {
		ObjectUtil.checkNotNull(poolName, "poolName");

		if (priority < Thread.MIN_PRIORITY || priority > Thread.MAX_PRIORITY) {
			throw new IllegalArgumentException(
					"priority: " + priority + " (expected: Thread.MIN_PRIORITY <= priority <= Thread.MAX_PRIORITY)");
		}

		prefix = poolName + '-' + poolId.incrementAndGet() + '-';
		this.daemon = daemon;
		this.priority = priority;
		this.threadGroup = threadGroup;
	}

	public DefaultThreadFactory(String poolName, boolean daemon, int priority) {
		this(poolName, daemon, priority, null);
	}

	public static String toPoolName(Class<?> poolType) {
		ObjectUtil.checkNotNull(poolType, "poolType");

		String poolName = StringUtil.simpleClassName(poolType);
		switch (poolName.length()) {
			case 0:
				return "unknown";
			case 1:
				return poolName.toLowerCase(Locale.US);
			default:
				if (Character.isUpperCase(poolName.charAt(0)) && Character.isLowerCase(poolName.charAt(1))) {
					return Character.toLowerCase(poolName.charAt(0)) + poolName.substring(1);
				} else {
					return poolName;
				}
		}
	}

	@Override
	public Thread newThread(Runnable r) {
		Thread t = newThread(FastThreadLocalRunnable.wrap(r), prefix + nextId.incrementAndGet());
		try {
			if (t.isDaemon() != daemon) {
				t.setDaemon(daemon);
			}

			if (t.getPriority() != priority) {
				t.setPriority(priority);
			}
		} catch (Exception ignored) {
			// Doesn't matter even if failed to set.
		}
		return t;
	}

	protected Thread newThread(Runnable r, String name) {
		return new FastThreadLocalThread(threadGroup, r, name);
	}
}
